﻿import Axios from 'axios'
import { storeToRefs } from 'pinia'
import { transformI18n } from '@/plugins/i18n'
import { AxiosHttpRequestConfig } from './types'
import { endLoading } from './loading'
import { useSystemConfigStoreWithOut } from '@/store/storage/systemConfigStore'
const systemConfigStore = useSystemConfigStoreWithOut()

// 全局是否取消重复请求、未完成请求的开关
const cancelDuplicated = true
// 存储处于pending状态的请求信息，用于比对移除哪一个
const pendingList = []
// 存储处于pending状态请求的map，用于取消请求
const pendingMap = new Map()

/**
 * 生成每个请求唯一的键
 * @param {*} config
 * @returns string
 */
const getPendingKey = (config) => {
  // eslint-disable-next-line prefer-const
  let { url, method, params, data } = config
  let getParams = null
  let urlPath = url
  if (url.indexOf('?') !== -1) {
    getParams = url.split('?')[1]
    urlPath = url.split('?')[0]
  }
  if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
  const pendingInfo = {
    pendingKey: [urlPath, method, JSON.stringify(params), JSON.stringify(data), getParams].join('&'),
    pendingPath: [urlPath, method].join('&'),
    pendingParams: [JSON.stringify(params), JSON.stringify(data), getParams].join('&')
  }
  return pendingInfo
}

/**
 * 储存每个请求唯一值, 也就是cancel()方法, 用于取消请求
 * @param {*} config
 */
const addPending = (config) => {
  const pendingInfo = getPendingKey(config)
  config.cancelToken =
    config.cancelToken ||
    new Axios.CancelToken((cancel) => {
      if (!pendingMap.has(pendingInfo.pendingKey)) {
        pendingMap.set(pendingInfo.pendingKey, cancel)
        pendingList.push(pendingInfo)
      }
    })
}
/**
 * 删除请求对列中的请求
 * @param {*} config
 */
const removePending = (config: AxiosHttpRequestConfig) => {
  if (!cancelDuplicated) return
  const pendingInfo = getPendingKey(config)
  if (pendingMap.has(pendingInfo.pendingKey)) {
    let pendingKeyIdx: number
    pendingList.forEach(function (item, index) {
      if (item.pendingKey === pendingInfo.pendingKey) {
        pendingKeyIdx = index
      }
    })
    const cancelToken = pendingMap.get(pendingInfo.pendingKey)
    cancelToken(pendingInfo.pendingKey)
    pendingMap.delete(pendingInfo.pendingKey)
    pendingList.splice(pendingKeyIdx, 1)
  }
}
/**
 * 请求拦截中根据请求的可能类型，做不同的逻辑操作
 * @param {*} config
 */
const judgeRending = (config: AxiosHttpRequestConfig) => {
  if (!cancelDuplicated) return
  const { systemConfig } = storeToRefs(systemConfigStore)
  // 判断是否存在列表中有，但是取消请求队列中没有的请求，这种属于路由切换被清空，但pendingList在监听路由中无法清空，需在这里将被清空的请求队列，移除数组
  if (pendingList.length > 0) {
    for (let i = 0; i < pendingList.length; i++) {
      if (!pendingMap.has(pendingList[i].pendingKey)) {
        pendingList.splice(i, 1)
        i--
      }
    }
  }
  const pendingType = pendingRequestType(config)
  switch (pendingType) {
    case 'repeat':
      // eslint-disable-next-line no-case-declarations
      let cancelFuc
      config.cancelToken = new Axios.CancelToken((cancel) => {
        cancelFuc = cancel
      })
      // eslint-disable-next-line no-case-declarations
      const errorMsg = `${config.url}` + transformI18n('errors.errorRequestBreakOff', true)
      // 阻止当前请求
      cancelFuc(errorMsg, config)
      if (systemConfig.value && systemConfig.value.isLoadingEnable && config.config.showLoading) {
        endLoading()
      }
      break
    case 'filter':
      removePending(config)
      addPending(config)
      break
    default:
      addPending(config)
      break
  }
}

// 判断请求类型
const pendingRequestType = (config: any) => {
  const pendingInfo = getPendingKey(config)
  let pendingType = 'normal'
  if (pendingList.length > 0) {
    pendingList.forEach(function (item) {
      // 请求地址、请求方法相同时
      if (item.pendingPath === pendingInfo.pendingPath) {
        if (item.pendingParams === pendingInfo.pendingParams) {
          pendingType = 'repeat' // 重复类型请求
        } else {
          pendingType = 'filter' // 筛选类多次请求
        }
      }
    })
  }
  return pendingType
}

export { pendingList, pendingMap, judgeRending, removePending }
